package com.zhengbing.tj.interceptor;

import com.zhengbing.tj.common.RequiresPermission;
import com.zhengbing.tj.common.RequiresRole;
import com.zhengbing.tj.common.UserContext;
import com.zhengbing.tj.entity.User;
import com.zhengbing.tj.service.PermissionService;
import com.zhengbing.tj.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 权限拦截器
 * 验证用户是否有权限访问特定资源
 *
 * @author zhengbing
 * @date 2024-08-22
 */
@Slf4j
@Component
public class PermissionInterceptor implements HandlerInterceptor {
    
    @Autowired
    private PermissionService permissionService;
    
    @Autowired
    private RoleService roleService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 白名单路径无需权限验证
        String requestURI = request.getRequestURI();
        if (isWhiteList(requestURI)) {
            return true;
        }
        
        // 检查是否是方法处理
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        
        // 获取当前用户
        User currentUser = UserContext.getUser();
        if (currentUser == null) {
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("{\"code\":401,\"message\":\"未登录，无法访问资源\"}");
            out.flush();
            out.close();
            return false;
        }
        
        // 检查是否有RequiresPermission注解
        if (method.isAnnotationPresent(RequiresPermission.class)) {
            RequiresPermission requiresPermission = method.getAnnotation(RequiresPermission.class);
            if (!checkPermission(currentUser.getId(), requiresPermission.value(), requiresPermission.requireAll())) {
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter out = response.getWriter();
                out.write("{\"code\":403,\"message\":\"权限不足，无法访问资源\"}");
                out.flush();
                out.close();
                return false;
            }
        }
        
        // 检查是否有RequiresRole注解
        if (method.isAnnotationPresent(RequiresRole.class)) {
            RequiresRole requiresRole = method.getAnnotation(RequiresRole.class);
            if (!checkRole(currentUser.getId(), requiresRole.value(), requiresRole.requireAll())) {
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter out = response.getWriter();
                out.write("{\"code\":403,\"message\":\"角色不足，无法访问资源\"}");
                out.flush();
                out.close();
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 检查用户是否有权限
     */
    private boolean checkPermission(Long userId, String[] permissionCodes, boolean requireAll) {
        List<com.zhengbing.tj.entity.Permission> permissions = permissionService.getPermissionsByUserId(userId);
        Set<String> userPermissionCodes = permissions.stream()
                .map(com.zhengbing.tj.entity.Permission::getCode)
                .collect(Collectors.toSet());
        
        if (requireAll) {
            // 需要所有权限
            return Arrays.stream(permissionCodes).allMatch(userPermissionCodes::contains);
        } else {
            // 只需要任一权限
            return Arrays.stream(permissionCodes).anyMatch(userPermissionCodes::contains);
        }
    }
    
    /**
     * 检查用户是否有角色
     */
    private boolean checkRole(Long userId, String[] roleCodes, boolean requireAll) {
        List<com.zhengbing.tj.entity.Role> roles = roleService.getRolesByUserId(userId);
        Set<String> userRoleCodes = roles.stream()
                .map(com.zhengbing.tj.entity.Role::getCode)
                .collect(Collectors.toSet());
        
        if (requireAll) {
            // 需要所有角色
            return Arrays.stream(roleCodes).allMatch(userRoleCodes::contains);
        } else {
            // 只需要任一角色
            return Arrays.stream(roleCodes).anyMatch(userRoleCodes::contains);
        }
    }
    
    /**
     * 检查是否是白名单路径
     */
    private boolean isWhiteList(String requestURI) {
        // 可以根据实际需求扩展白名单
        String[] whiteList = {
            "/swagger-ui/", "/v3/api-docs/",
            "/swagger-resources/",
            "/doc.html", "/webjars/",
            "/api/users/login", "/api/users/register"
        };
        
        for (String path : whiteList) {
            if (requestURI.startsWith(path)) {
                return true;
            }
        }
        return false;
    }
}